import argparse
from docx import Document
from docx.shared import Pt, Inches
from docx.oxml.ns import qn
from docx.enum.text import WD_LINE_SPACING, WD_BREAK, WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
import re

# 自动分页

# 修改段落样式函数
def modify_paragraph_style(paragraph, font_name, chinese_font_name, font_size, line_spacing, line_spacing_rule, first_line_indent_chars):
    if not paragraph.style.name.startswith(('Heading', 'TOC')):
        for run in paragraph.runs:
            run.font.name = font_name  # 设置字体
            run._element.rPr.rFonts.set(qn('w:eastAsia'), chinese_font_name)  # 设置中文字体
            run.font.size = Pt(font_size)  # 设置字号
        paragraph_format = paragraph.paragraph_format
        if line_spacing_rule == 0:
            paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
            paragraph_format.line_spacing = line_spacing  # 设置多倍行距
        else:
            paragraph_format.line_spacing = Pt(line_spacing)  # 设置固定行间距

        # 设置首行缩进，以字符为单位，假设每个字符平均宽度为0.5
        paragraph_format.first_line_indent = Pt(font_size*2)

# 修改标题样式函数
def modify_heading_style(paragraph, font_name, chinese_font_name, font_size, line_spacing, line_spacing_rule, first_line_indent_chars, center_heading):
    if paragraph.style.name.startswith(('Heading', 'TOC')):
        for run in paragraph.runs:
            run.font.name = font_name  # 设置标题字体
            run._element.rPr.rFonts.set(qn('w:eastAsia'), chinese_font_name)  # 设置标题中文字体
            run.font.size = Pt(font_size)  # 设置标题字号
        paragraph_format = paragraph.paragraph_format
        if line_spacing_rule == 0:
            paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
            paragraph_format.line_spacing = line_spacing  # 设置标题行间距
        else:
            paragraph_format.line_spacing = Pt(line_spacing)  # 设置标题固定行间距

        # 设置标题首行缩进，以字符为单位，假设每个字符平均宽度为0.25
        # paragraph_format.first_line_indent = Inches(first_line_indent_chars * 0.25)
        paragraph_format.first_line_indent = Pt(font_size*2)

        # 如果需要居中对齐标题
        if center_heading:
            paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER

# 插入分页符函数
def insert_page_break(paragraph):
    # 插入分页符
    paragraph.insert_paragraph_before().add_run().add_break(WD_BREAK.PAGE)

# 检查段落是否为空白
def is_empty_paragraph(paragraph):
    return not paragraph.text.strip()  # 使用strip()确保空白字符被正确检测

# 判断当前段落是否在新页面
def is_paragraph_on_new_page(paragraph):
    # 通过分析段落的底层 XML 判断是否有分页符
    for run in paragraph.runs:
        if 'lastRenderedPageBreak' in run._element.xml or 'w:br' in run._element.xml:
            return True
    return False

# 判断是否已经有分页符
def has_page_break_before(paragraph):
    prev = paragraph._element.getprevious()  # 获取前一个段落的 XML 元素
    if prev is not None:
        # 检查前一个段落的 XML 是否有分页符
        for child in prev:
            if child.tag.endswith('br') and child.get('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}type') == 'page':
                return True
    return False

# 判断段落前面是否有空白回车符
def has_blank_line_before(paragraph):
    prev = paragraph._element.getprevious()  # 获取前一个段落的 XML 元素
    if prev is not None:
        # 检查前一个段落的文本是否为空
        if prev.text is None or prev.text.strip() == '':
            return True
    return False

# 判断段落前面是否有表格
def has_table_before(paragraph):
    prev = paragraph._element.getprevious()  # 获取前一个段落的 XML 元素
    while prev is not None:
        # 检查当前元素是否为表格
        if prev.tag.endswith('tbl'):
            return True
        # 移动到前一个元素
        prev = prev.getprevious()
    return False

# 插入目录域代码
def insert_table_of_contents(doc):
    # 查找“目 录”标题的段落
    toc_title_index = -1
    toc_title_pattern = re.compile(r'\b目\s*录\b')

    for i, paragraph in enumerate(doc.paragraphs):
        if toc_title_pattern.match(paragraph.text.strip()):
            toc_title_index = i
            break

    # 插入目录内容
    toc_content = []
    for paragraph in doc.paragraphs:
        if paragraph.style.name.startswith('Heading'):
            # 获取标题级别和标题文本
            level = int(paragraph.style.name.split()[-1])
            text = paragraph.text.strip()
            if text:
                toc_content.append((level, text))

    # 在“目 录”标题段落之后插入目录
    toc_paragraphs = []
    for level, text in toc_content:
        indent = '    ' * (level - 1)  # 根据标题级别设置缩进
        toc_entry = f'{indent}{text}'
        toc_paragraphs.append(toc_entry)

    # 将目录内容添加到“目 录”标题下
    toc_paragraph = doc.paragraphs[toc_title_index + 1]
    count = 0
    for entry in toc_paragraphs:
        if count == 0:
            toc_paragraph.add_run('\n'+entry + '\n')
            count += 1
        else:
            toc_paragraph.add_run(entry + '\n')

# 修改文档函数
def modify_document(filepath, save_path, skip_paragraphs, font_name, chinese_font_name, font_size, line_spacing, line_spacing_rule,
                    heading_font_name, heading_chinese_font_name, heading_font_size, heading_line_spacing, heading_line_spacing_rule,
                    first_line_indent_chars, heading_first_line_indent_chars, auto_page_break, center_heading, insert_toc):
    # 打开文档
    doc = Document(filepath)
    paragraphs = doc.paragraphs
    i = 0

            # 插入目录
    if insert_toc:
        insert_table_of_contents(doc)

    # 跳过指定的段落数
    for _ in range(skip_paragraphs):
        if i < len(paragraphs):
            i += 1

    # 从跳过的段落开始，修改内容并删除空白段落
    for j in range(i, len(paragraphs)):
        paragraph = paragraphs[j]


        # 跳过空白段落
        if is_empty_paragraph(paragraph):
            continue

        # 检查是否是一级标题，并根据条件插入分页符
        if auto_page_break and paragraph.style.name == 'Heading 1':
            if j > 0:
                # 如果前面的段落不是空的，并且标题不是在新页面上，并且没有分页符，才插入分页符
                if not has_blank_line_before(paragraphs[j-1]) and not is_paragraph_on_new_page(paragraph) and not has_page_break_before(paragraph) and has_table_before(paragraph):
                    insert_page_break(paragraph)
                # 如果前面的段落是表格，并且标题不是在新页面上，并且没有分页符，才插入分页符
                elif has_table_before(paragraph) and not is_paragraph_on_new_page(paragraph) and not has_page_break_before(paragraph):
                    insert_page_break(paragraph)

        # 根据段落类型选择修改样式
        if paragraph.style.name.startswith(('Heading', 'TOC')):
            modify_heading_style(paragraph, heading_font_name, heading_chinese_font_name, heading_font_size, heading_line_spacing, heading_line_spacing_rule, heading_first_line_indent_chars, center_heading)
        else:
            modify_paragraph_style(paragraph, font_name, chinese_font_name, font_size, line_spacing, line_spacing_rule, first_line_indent_chars)

    # 保存文档到指定路径
    doc.save(save_path)
    return save_path

# 主函数
def main():
    parser = argparse.ArgumentParser(description='Modify the paragraph and heading styles of a Word document, with optional automatic page breaks.')
    parser.add_argument('filepath', type=str, help='Path to the input Word document')
    parser.add_argument('save_path', type=str, help='Path to save the modified Word document')
    parser.add_argument('--skip_paragraphs', type=int, default=0, help='Number of paragraphs to skip (default: 0)')
    parser.add_argument('--insert_toc', action='store_true', help='Insert a table of contents at the beginning of the document')
    # 普通段落参数
    parser.add_argument('--font_name', type=str, default='宋体', help='Font name to apply to paragraphs (default: 宋体)')
    parser.add_argument('--chinese_font_name', type=str, default='宋体', help='Chinese font name to apply to paragraphs (default: 宋体)')
    parser.add_argument('--font_size', type=float, default=22, help='Font size to apply to paragraphs (default: 16)')
    parser.add_argument('--line_spacing', type=float, default=1, help='Line spacing to apply to paragraphs (default: 1)')
    parser.add_argument('--line_spacing_rule', type=int, default=0, help='Line spacing rule to apply to paragraphs (default: 0)')
    parser.add_argument('--first_line_indent_chars', type=int, default=0, help='First line indent for paragraphs in characters (default: 0)')

    # 标题参数
    parser.add_argument('--heading_font_name', type=str, default='方正小标宋简体', help='Font name to apply to headings (default: Arial)')
    parser.add_argument('--heading_chinese_font_name', type=str, default='方正小标宋简体', help='Chinese font name to apply to headings (default: 宋体)')
    parser.add_argument('--heading_font_size', type=float, default=22, help='Font size to apply to headings (default: 22)')
    parser.add_argument('--heading_line_spacing', type=float, default=1.5, help='Line spacing to apply to headings (default: 1.5)')
    parser.add_argument('--heading_line_spacing_rule', type=int, default=0, help='Line spacing rule to apply to headings (default: 0)')
    parser.add_argument('--heading_first_line_indent_chars', type=int, default=0, help='First line indent for headings in characters (default: 0)')

    # 标题居中对齐参数
    parser.add_argument('--center_heading', action='store_true', help='Center align the headings')

    # 自动分页
    parser.add_argument('--auto_page_break', action='store_true', help='Automatically insert page breaks before Heading 1')

    args = parser.parse_args()

    modify_document(
        filepath=args.filepath,
        save_path=args.save_path,
        skip_paragraphs=args.skip_paragraphs,
        font_name=args.font_name,
        chinese_font_name=args.chinese_font_name,
        font_size=args.font_size,
        line_spacing=args.line_spacing,
        line_spacing_rule=args.line_spacing_rule,
        heading_font_name=args.heading_font_name,
        heading_chinese_font_name=args.heading_chinese_font_name,
        heading_font_size=args.heading_font_size,
        heading_line_spacing=args.heading_line_spacing,
        heading_line_spacing_rule=args.heading_line_spacing_rule,
        first_line_indent_chars=args.first_line_indent_chars,
        heading_first_line_indent_chars=args.heading_first_line_indent_chars,
        auto_page_break=args.auto_page_break,
        center_heading=args.center_heading,
        insert_toc=args.insert_toc
    )

if __name__ == '__main__':
    main()
